import type { CreateBrowsingHistoryInput } from '#/database/types'
import type { WebContents, WebPreferences } from 'electron'

import { databaseManager } from '#/database/database-manager'
import { createContextMenu } from '#/modules/menu-browser'
import { idGenerator } from '#/modules/id-generator'
import { attachPasswordAutofillInjector } from '#/modules/frame-injector'
import { TypedEventEmitter } from '#/utils/events'
import { getPreloadPath } from '#/utils/paths'
import { extractProtocol, isHttpProtocol, isProtocolRegistered } from '#/utils/protocols'
import urlManager, { isInternalUrl } from '#/utils/urls'
import { shell, WebContentsView } from 'electron'
import { WINDOW_STYLE_CONSTANTS } from '~shared/constants/layout'
import { createURLWithParams, formatUrl } from '~shared/utils/urlUtils'
import { tabTopic, toolbarTopic } from '~shared/ipc-topic'
import { CreateState, createStorageState } from 'global-state'

export type TabConfig = {
  sidebarConfig: F2.tab.Entity['sidebarConfig']
  isInSeparateWindow?: boolean
}

// 创建tab配置状态管理器方法
export function createTabConfigState(tabId: number) {
  return createStorageState(
    `tabConfig-${tabId}`,
    {
      isInSeparateWindow: undefined
    } as TabConfig,
    1,
    { skipDefaultsCheck: true }
  )
}

type TabEvents = {
  inited: () => void
  'data:change': (tab: F2.tab.Patch) => void
  closed: (tab: F2.tab.Entity) => void
  'separate-window:toggle': (tab: Tab) => void // 标签页是否独立窗口状态切换
  'width:change': (width: number) => void
  'fullscreen:change': (fullscreen: boolean) => void
  'separate-config:change': (config: F2.tab.Entity['separateConfig']) => void
}

// 桌面端用户代理
const USER_AGENT =
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' +
  'AppleWebKit/537.36 (KHTML, like Gecko) ' +
  'Chrome/139.0.0.0 Safari/537.36 ' +
  'Edg/139.0.0.0'
// 移动端用户代理
const MOBILE_USER_AGENT =
  'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) ' +
  'AppleWebKit/537.36 (KHTML, like Gecko) ' +
  'Chrome/139.0.0.0 Mobile Safari/537.36 ' +
  'Edg/139.0.0.0'

interface Options {
  useTransparent?: boolean // 是否使用透明背景
  borderRadius?: number
  webPreferences?: WebPreferences
}

/**
 * 标签页实体类
 * 所有标签页实例都继承自该类
 **/
class Tab extends TypedEventEmitter<TabEvents> {
  data: F2.tab.Entity
  view: WebContentsView
  private options?: Options
  private fallbackPageUrl: string = urlManager.buildFileUrl('fallbackPage')
  // 是否初始化完成
  private isInited = false
  private _isDestroyed = false
  private hasRecorded: boolean
  private tabConfig?: CreateState<TabConfig>
  htmlFullScreen = false

  get id() {
    return this.data.id
  }

  get webContentsId() {
    return this.data.webContentsId
  }

  get sidebarWidth() {
    return this.data.sidebarConfig?.width ?? WINDOW_STYLE_CONSTANTS.SIDEBAR_VIEW_DEFAULT_WIDTH
  }

  get separateConfig() {
    return this.data.separateConfig
  }

  get isPinned() {
    return this.data.sidebarConfig?.isPinned
  }

  get isDestroyed() {
    return this._isDestroyed
  }

  /**
   * 标签页构造函数
   * @param tabParam - 标签页参数
   * @param options  - 选项
   * */
  constructor(tabParam: F2.tab.Create, options?: Options) {
    super()
    this.options = options
    const { tab, view } = this.createTabView(tabParam, options?.webPreferences)
    this.data = tab
    this.view = view

    // 增加事件监听
    this.setupWebContentsEventListeners()

    // 初始化浏览历史记录状态
    this.hasRecorded = false

    this.view.webContents.setUserAgent(this.data.isMobile ? MOBILE_USER_AGENT : USER_AGENT)

    this.openUrl(this.data.url)
      .catch(error => {
        if (error.errno === -3) return
        console.error(`标签页${this.data.url} 加载失败:`, error)
      })
      .finally(() => {
        this.isInited = true
        this.emit('inited')
      })
    global.tabMap.set(this.webContentsId, this)
  }

  /**
   * 在独立窗口中关闭标签页
   * */
  close() {
    console.log(`标签页 ${this.data.id} 已关闭`)
    this.destroy()
    this.emit('closed', this.data)
  }

  loadURL(url?: string) {
    if (url) {
      return this.view.webContents.loadURL(urlManager.toFileUrl(url))
    } else {
      // 当url为空时，加载默认首页
      return this.view.webContents.loadURL(this.fallbackPageUrl)
    }
  }

  /**
   * 打开指定url
   * @param url 要打开的url,如果为空，则打开
   */
  openUrl(url?: string) {
    if (url) url = formatUrl(url)

    this.data.state.error = void 0
    if (url !== this.data.url) {
      this.data.url = url ?? ''
      this.data.title = ''
      this.data.favicon = ''
      this.updateData(this.data)
    }
    this.view.setBackgroundColor('rgba(0,0,0,0)')

    return this.loadURL(url)
  }

  // 设置用户代理
  toggleUserAgent() {
    this.data.isMobile = !this.data.isMobile
    this.view.webContents.setUserAgent(this.data.isMobile ? MOBILE_USER_AGENT : USER_AGENT)
    this.view.webContents.reload()
    this.updateData({ isMobile: this.data.isMobile })
  }

  // 设置标签页侧边栏时显示的宽度
  setWidth(width: number) {
    if (!this.data.sidebarConfig) this.data.sidebarConfig = {}
    this.data.sidebarConfig.width = width
    this.updateData({ sidebarConfig: this.data.sidebarConfig })
    this.tabConfig?.set('sidebarConfig', this.data.sidebarConfig)
    this.emit('width:change', width)
  }

  /**
   * 设置 ESC 事件优先级
   * @param priority 数值越大优先级越高；<=0 视为不处理
   */
  setEscPriority(priority: number) {
    const p = Number(priority) || 0
    this.data.escPriority = Math.max(p, 0)
    this.updateData({ escPriority: this.data.escPriority })
  }

  /**
   * 设置工具栏配置（用于独立窗口）
   * @param config 工具栏配置对象
   */
  setToolbarConfig(config: F2.toolbar.Config) {
    this.data.toolbarConfig = config
    this.updateData({ toolbarConfig: config })
  }

  /**
   * 设置标签页独立窗口配置
   * @param config 独立窗口配置对象
   * */
  setSeparateConfig(config: F2.tab.Entity['separateConfig']) {
    this.data.separateConfig = config
    this.updateData({ separateConfig: config })
    this.emit('separate-config:change', config)
  }

  /**
   * 设置数据
   * @param data 要设置的数据
   * */
  setData(data: unknown) {
    this.data.data = data
    this.updateData({ data })
  }

  /**
   * 工具栏单击转发
   * @param buttonId 工具栏按钮ID
   * */
  toolbarButtonClick(buttonId: string) {
    this.view.webContents.send(toolbarTopic.buttonClick, { buttonId })
  }

  /**
   * 切换是否固定标签页
   * */
  togglePinned() {
    if (!this.data.sidebarConfig) this.data.sidebarConfig = {}
    this.data.sidebarConfig.isPinned = !this.data.sidebarConfig.isPinned
    this.tabConfig?.set('sidebarConfig', this.data.sidebarConfig)
    this.updateData({ sidebarConfig: this.data.sidebarConfig })
  }

  /**
   * 翻译状态
   * */
  toggleTranslationState(data: F2.tab.TranslationState) {
    this.data.state.translation = data

    // 在 E2E 环境下，测试直接从主进程读取状态，为避免跨进程序列化报错，
    // 不再向渲染进程广播完整的 Tab 数据补丁。
    if (process.env.E2E === 'true') return

    this.updateData({ state: this.data.state })
  }

  /**
   * 切换标签页是否在新窗口中打开
   * */
  toggleInSeparateWindow() {
    this.data.isInSeparateWindow = !this.data.isInSeparateWindow
    this.updateData({ isInSeparateWindow: this.data.isInSeparateWindow })
    this.tabConfig?.set('isInSeparateWindow', this.data.isInSeparateWindow)

    this.emit('separate-window:toggle', this)
  }

  /**
   * 翻译页面
   * */
  translatePage(language: string) {
    this.view.webContents.send('translate-page', language)
  }

  /**
   * 返回原文
   * */
  restoreOriginal() {
    this.view.webContents.send('restore-original')
  }

  /**
   * 切换标签页静音状态
   */
  toggleMute() {
    if (this.isDestroyed) return
    const wasAudioMuted = this.view.webContents.isAudioMuted()
    this.view.webContents.setAudioMuted(!wasAudioMuted)
    this.data.state.isMuted = !wasAudioMuted

    this.updateData({ state: this.data.state })
  }

  /**
   * 设置标签页历史记录启用状态
   */
  toggleHistoryEnabled() {
    if (this.isDestroyed) return
    this.data.enableHistory = !this.data.enableHistory
    this.updateData({ enableHistory: this.data.enableHistory })

    console.log(`标签页 ${this.data.id} 历史记录已${this.data.enableHistory ? '启用' : '禁用'}`)
  }

  /**
   * 聚焦标签页
   * */
  focus() {
    this.view.webContents.focus()
  }

  // 查找页面发起者
  findSender: WebContents | null = null
  /**
   * 从页面上查找文本
   * @param text 要查找的文本
   * @param options 选项
   * @param sender 发送者
   *
   * */
  findInPage(text: string, options: Electron.FindInPageOptions, sender: WebContents) {
    this.findSender = sender
    this.view.webContents.findInPage(text, options)
  }

  /**
   * 停止查找文本
   * */
  stopFindInPage(sender: WebContents) {
    this.findSender = sender
    this.view.webContents.stopFindInPage('clearSelection')
  }

  /**
   * 处理页面导航完成的历史记录
   */
  private handlePageNavigationComplete(): void {
    // 检查是否启用历史记录
    if (this.data.enableHistory === false) {
      return
    }

    // 过滤掉内部页面和无效URL
    if (this.shouldSkipUrl(this.data.url)) {
      return
    }

    // 更新状态

    this.hasRecorded = false

    // 立即记录 URL，类似 Chrome 的行为
    this.recordCurrentPage().then()
  }

  /**
   * 记录当前页面到历史记录
   */
  private async recordCurrentPage(): Promise<void> {
    if (this.hasRecorded || this.isDestroyed) {
      return
    }

    // 检查URL有效性
    if (this.shouldSkipUrl(this.data.url)) {
      return
    }

    try {
      // 获取数据库服务
      if (!databaseManager.isReady()) {
        console.warn('⚠️ 数据库管理器未就绪，跳过历史记录')
        return
      }

      const browsingHistoryService = databaseManager.getBrowsingHistoryService()

      // 立即记录 URL，标题和图标可能为空（后续会更新）
      const historyInput: CreateBrowsingHistoryInput = {
        url: this.data.url,
        title: this.data.title,
        favicon_url: this.data.favicon || undefined
      }

      const result = await browsingHistoryService.addOrUpdateRecord(historyInput)

      if (result.success) {
        this.hasRecorded = true
        // console.log(
        //   `✅ 标签页 ${this.data.id} 历史记录已保存: ${historyInput.title || this.data.url}`
        // )
      } else {
        console.error(`❌ 标签页 ${this.data.id} 历史记录保存失败: ${result.error}`)
      }
    } catch (error) {
      console.error(`❌ 标签页 ${this.data.id} 记录历史时发生错误:`, error)
    }
  }

  /**
   * 判断是否应该跳过记录该URL
   * @param url URL
   * @returns 是否跳过
   */
  private shouldSkipUrl(url: string): boolean {
    if (!url) return true

    // 跳过的URL模式
    const skipPatterns = [
      /^about:/,
      /^chrome:/,
      /^chrome-extension:/,
      /^moz-extension:/,
      /^edge:/,
      /^data:/,
      /^blob:/,
      /^javascript:/
    ]
    // 检查是否为应用内部页面, 跳过
    if (isInternalUrl(url)) {
      return true
    }

    return skipPatterns.some(pattern => pattern.test(url))
  }

  /**
   * 更新已存在的历史记录
   * @param updates 更新内容
   */
  private async updateHistoryRecord(updates: {
    title?: string
    favicon_url?: string
  }): Promise<void> {
    // 检查是否启用历史记录且已记录过
    if (this.data.enableHistory === false || !this.hasRecorded || !this.data.url) {
      return
    }

    try {
      if (!databaseManager.isReady()) {
        return
      }

      const browsingHistoryService = databaseManager.getBrowsingHistoryService()

      // 查找现有记录
      const findResult = await browsingHistoryService.findByUrl(this.data.url)
      if (findResult.success && findResult.data) {
        // 更新记录
        const updateResult = await browsingHistoryService.updateRecord(
          findResult.data._id.toString(),
          updates
        )

        if (updateResult.success) {
          // console.log(`🔄 标签页 ${this.data.id} 历史记录已更新: ${this.data.url}`)
        }
      }
    } catch (error) {
      console.error(`❌ 标签页 ${this.data.id} 更新历史记录时发生错误:`, error)
    }
  }

  /**
   * 销毁标签页实例，清理所有事件监听器和资源
   */
  destroy() {
    if (this.isDestroyed) return

    global.tabMap.delete(this.webContentsId)

    this._isDestroyed = true

    // 清理浏览历史记录状态
    this.hasRecorded = false

    // 移除所有 WebContents 事件监听器
    this.view.webContents.removeAllListeners()
    // 移除窗口打开处理器
    this.view.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))

    // 关闭 WebContents
    if (!this.view.webContents.isDestroyed()) {
      this.view.webContents.close()
    }

    setImmediate(() => {
      // 移除所有自定义事件监听器
      this.removeAllListeners()
      console.log(`Tab ${this.data.id} destroyed and cleaned up`)
    })
  }

  /**
   * 生成默认的数据对象
   */
  createNewData = (
    overrides: Partial<F2.tab.Entity> = {},
    webContentsId: number
  ): F2.tab.Entity => {
    const data: F2.tab.Entity = {
      type: 'tab',
      id: overrides?.id || idGenerator.generateId('tab'),
      title: '',
      url: '',
      webContentsId,
      nav: {
        isLoading: false,
        canGoBack: false,
        canGoForward: false
      },
      state: {
        isPlaying: false,
        isMuted: false,
        translation: undefined,
        error: undefined
      },
      // ESC 事件优先级（0 表示不处理）
      escPriority: 0,
      enableHistory: true, // 默认启用历史记录
      ...overrides // 允许通过参数覆盖默认值
    }

    if (data.id < 0) {
      this.tabConfig = createTabConfigState(data.id)

      // 判断是否使用存储默认值
      if (this.tabConfig.state.sidebarConfig?.isPinned !== undefined) {
        if (!data.sidebarConfig) data.sidebarConfig = {}

        data.sidebarConfig.isPinned = this.tabConfig.state.sidebarConfig.isPinned
      }
      // 判断是否使用存储默认值
      if (this.tabConfig.state.isInSeparateWindow !== undefined) {
        data.isInSeparateWindow = this.tabConfig.state.isInSeparateWindow
      }
      // 判断是否使用存储默认值
      if (this.tabConfig.state.sidebarConfig?.width !== undefined) {
        if (!data.sidebarConfig) data.sidebarConfig = {}

        data.sidebarConfig.width = this.tabConfig.state.sidebarConfig.width
      }
    }
    if (data.url) {
      data.url = decodeURI(data.url)
    }
    return data
  }

  // 是否为回退页面
  private shouldSkipUpdate(): boolean {
    const d = this.isDestroyed || this.view.webContents.getURL().includes(this.fallbackPageUrl)
    if (d) {
      if (!this.isDestroyed) {
        this.data.nav.canGoBack = this.view.webContents.navigationHistory.canGoBack()
        this.data.nav.canGoForward = this.view.webContents.navigationHistory.canGoForward()
        this.data.title = ''
        this.data.favicon = ''
        this.updateData(this.data)
      }

      return true
    } else {
      return false
    }
  }

  /**
   * 设置 WebContents 事件监听器
   */
  setupWebContentsEventListeners() {
    const view = this.view,
      data = this.data
    if (!this.options?.useTransparent) {
      view.webContents.on('dom-ready', () => {
        setTimeout(() => {
          view.setBackgroundColor('#FFFFFF')
        }, 500)
      })
    }

    createContextMenu(view.webContents, data)

    // 页面加载失败
    const errorHandler = (errorCode: number, errorDescription: string) => {
      data.state.error = {
        code: errorCode,
        msg: errorDescription
      }
      data.nav.isLoading = false

      this.loadURL(
        createURLWithParams('f2://fallbackPage', {
          url: view.webContents.getURL(),
          code: errorCode.toString(),
          msg: errorDescription
        })
      ).catch(error => {
        if (error.errno === -3) return
        console.error(`标签页${this.data.url} 加载失败:`, error)
      })

      this.updateData({
        state: data.state,
        nav: data.nav
      })
    }

    // 监听页面加载失败
    view.webContents.on(
      'did-fail-load',
      (_, errorCode, errorDescription, validatedURL, isMainFrame) => {
        if (this.isDestroyed || !isMainFrame || errorCode === -3) return
        // console.log('did-fail-load', errorCode, errorDescription, validatedURL, isMainFrame)
        errorHandler(errorCode, errorDescription)
      }
    )

    // 监听即将导航事件，用于拦截侧栏标签页的域名跳转
    view.webContents.on('will-navigate', async (event, navigationUrl) => {
      if (this.isDestroyed) return

      // console.log(`即将导航: ${navigationUrl}`)
      if (!isHttpProtocol(navigationUrl)) {
        event.preventDefault()
        // 提取协议
        const protocol = extractProtocol(navigationUrl)
        // 判断协议是否存在
        if (protocol && (await isProtocolRegistered(protocol))) {
          console.log(`协议已注册: ${protocol}`)
          await shell.openExternal(navigationUrl)
        } else {
          console.log(`协议未注册: ${protocol}`)
        }
      }
    })

    // 监听页面导航
    const handleNavigation = (
      /**
       * -1 for non HTTP navigations
       */
      httpResponseCode: number,
      /**
       * empty for non HTTP navigations
       */
      httpStatusText: string
    ) => {
      if (httpResponseCode >= 400) {
        errorHandler(httpResponseCode, httpStatusText)
        return
      }

      if (this.shouldSkipUpdate()) {
        return
      }
      const specialUrl = urlManager.toAppUrl(view.webContents.getURL())

      data.nav.canGoBack = view.webContents.navigationHistory.canGoBack()
      data.nav.canGoForward = view.webContents.navigationHistory.canGoForward()
      data.url = decodeURIComponent(specialUrl)
      data.state.error = void 0

      this.updateData({
        url: data.url,
        state: data.state,
        nav: data.nav
      })

      // 处理页面导航完成的历史记录
      this.handlePageNavigationComplete()
    }

    view.webContents.on('did-navigate', (_, url, httpResponseCode, httpStatusText) => {
      handleNavigation(httpResponseCode, httpStatusText)
    })
    view.webContents.on('did-navigate-in-page', () => {
      handleNavigation(200, 'OK')
    })

    // 监听页面开始加载
    view.webContents.on('did-start-loading', () => {
      if (this.isDestroyed) return
      if (view.webContents.getURL().includes(this.fallbackPageUrl)) {
        data.title = ''
      } else {
        data.state.error = void 0
      }

      data.nav.isLoading = true

      this.updateData({
        nav: data.nav,
        state: data.state,
        title: data.title
      })

      // 重置历史记录状态
      if (data.enableHistory !== false) {
        this.hasRecorded = false
      }
    })

    // 监听页面停止加载
    view.webContents.on('did-stop-loading', () => {
      if (this.isDestroyed) return
      data.nav.isLoading = false
      this.updateData({
        nav: data.nav
      })
    })

    // 监听图标变化
    view.webContents.on('page-favicon-updated', (_, faviconUrl) => {
      if (this.shouldSkipUpdate()) {
        return
      }

      if (data?.favicon === faviconUrl[0]) return
      data.favicon = faviconUrl[0]

      this.updateData({
        favicon: data.favicon
      })

      // 更新历史记录中的图标
      if (faviconUrl && faviconUrl.length > 0) {
        this.updateHistoryRecord({ favicon_url: faviconUrl[0] })
      }
    })

    // 监听标题变化
    view.webContents.on('page-title-updated', (_, title) => {
      if (this.shouldSkipUpdate()) {
        return
      }
      data.title = title
      this.updateData({
        title: data.title
      })

      // 更新历史记录中的标题
      this.updateHistoryRecord({ title })
    })

    // 链接悬停预览：转发 update-target-url 到渲染进程（externalWeb 监听）
    view.webContents.on('update-target-url', (_event, url) => {
      try {
        // 与预加载中监听的频道保持一致
        view.webContents.send('update-target-url', url)
      } catch (error) {
        console.warn('[Tab] 转发 update-target-url 失败:', error)
      }
    })

    // 监听页面进程崩溃，需要清除tab
    view.webContents.on('render-process-gone', () => {
      if (this.isDestroyed) return
      this.close()
      console.log('页面进程崩溃，需要清除tab', data.id)
    })

    // 监听多个媒体相关事件来确保状态准确
    // 监听媒体播放状态变化
    // 使用更可靠的方式检测媒体播放状态
    view.webContents.on('audio-state-changed', e => {
      if (this.isDestroyed) return

      data.state.isPlaying = e.audible
      this.updateData({
        state: data.state
      })
    })

    // HTML 全屏进入/退出事件，通知窗口控制器
    view.webContents.on('enter-html-full-screen', () => {
      this.htmlFullScreen = true
      this.emit('fullscreen:change', this.htmlFullScreen)
    })
    view.webContents.on('leave-html-full-screen', () => {
      this.htmlFullScreen = false
      this.emit('fullscreen:change', this.htmlFullScreen)
    })

    // 监听页面查找文本
    view.webContents.on('found-in-page', (_, result) => {
      if (this.findSender) {
        this.findSender.send(tabTopic.onFindInPage, result, this.webContentsId)
      } else {
        view.webContents.send(tabTopic.onFindInPage, result, this.webContentsId)
        view.webContents.focus()
      }
    })

    // Attach cross-origin frame injector (password autofill bridge)
    attachPasswordAutofillInjector(view.webContents)
  }

  /**
   * 重置标签页事件
   * */
  resetEvents() {
    this.removeAllListeners()
    this.view.webContents.removeAllListeners()
    this.setupWebContentsEventListeners()
  }

  private updateData(data: Partial<F2.tab.Entity>) {
    const u = {
      id: this.data.id,
      ...data
    }
    this.emit('data:change', u)
    // 通知给该view的渲染进程
    this.view.webContents.send(tabTopic.onUpdate, u)
  }

  /**
   * 新增：统一创建WebContentsView的方法
   * @param TabParam Partial<BrowserTab>
   * @param webPreferences 视图的webPreferences
   * @returns 视图
   */
  private createTabView(TabParam: Partial<F2.tab.Entity>, webPreferences?: WebPreferences) {
    const view = new WebContentsView({
      webPreferences: {
        transparent: true,
        preload: getPreloadPath(TabParam?.id && TabParam.id < 0 ? 'internal' : 'external'),
        ...webPreferences
      }
    })
    if (this.options?.borderRadius) {
      view.setBorderRadius(this.options.borderRadius)
    }

    const data = this.createNewData(TabParam, view.webContents.id)

    return {
      view,
      tab: data
    }
  }

  /**
   * 为翻译数据添加事件监听器
   * */
  goBack() {
    if (this.view.webContents.navigationHistory.canGoBack()) {
      this.view.webContents.navigationHistory.goBack()
    }
  }

  goForward() {
    if (this.view.webContents.navigationHistory.canGoForward()) {
      this.view.webContents.navigationHistory.goForward()
    }
  }

  reload() {
    this.view.setBackgroundColor('rgba(0,0,0,0)')
    if (this.data.url) {
      this.loadURL(this.data.url)
    } else {
      this.view.webContents.reload()
    }
  }

  stop() {
    this.view.webContents.stop()
  }
}

export { Tab }
